#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

// 服务器配置
#define SERVER_IP "192.168.2.77"
#define SERVER_PORT 60000

#define FILENAME "users.txt"
#define ACCOUNT_LENGTH 10
#define MAX_ATTEMPTS 100
#define MAX_CLIENTS 100

// 用户信息结构体
struct account_info {
    char a[ACCOUNT_LENGTH + 1];     // 账号
    char user_name[30];             // 用户名
    char password[30];              // 密码
    struct sockaddr_in client_addr; // 地址结构体
};

// 登录信息结构体
struct login_info {
    char identifier[30]; // 用户名或账号
    char password[30];
};

// 在线用户节点
struct online_user {
    char account[ACCOUNT_LENGTH + 1];
    char username[30];
    int socket_fd;
    struct sockaddr_in addr;
    struct online_user *next;
};

// 客户端上下文结构体
struct client_context {
    int socket_fd;
    struct sockaddr_in client_addr;
    char ip[16];
    int port;
    
    // 状态机状态
    enum {
        STATE_NORMAL,
        STATE_WAITING_FOR_REG_INFO,
        STATE_WAITING_FOR_LOGIN_INFO
    } state;
    
    char current_account[ACCOUNT_LENGTH+1];
    char current_username[30];
    char generated_account[ACCOUNT_LENGTH+1];
};

// 全局在线用户列表
struct online_user *online_list = NULL;
struct client_context *clients[MAX_CLIENTS];
int client_count = 0;

// 添加在线用户
void add_online_user(const char *account, const char *username, int socket_fd, struct sockaddr_in addr) {
    struct online_user *new_user = malloc(sizeof(struct online_user));
    if (!new_user) {
        perror("内存分配失败");
        return;
    }

    strncpy(new_user->account, account, ACCOUNT_LENGTH);
    strncpy(new_user->username, username, 29);
    new_user->socket_fd = socket_fd;
    new_user->addr = addr;
    new_user->next = online_list;
    online_list = new_user;
}

// 移除在线用户
void remove_online_user(int socket_fd) {
    struct online_user **ptr = &online_list;
    while (*ptr != NULL) {
        if ((*ptr)->socket_fd == socket_fd) {
            struct online_user *temp = *ptr;
            *ptr = (*ptr)->next;
            free(temp);
            break;
        }
        ptr = &(*ptr)->next;
    }
}

// 获取在线用户列表字符串
char *get_online_users() {
    // 计算所需缓冲区大小
    int size = 10; // "ONLINE:"
    struct online_user *current = online_list;
    while (current != NULL) {
        size += strlen(current->account) + strlen(current->username) + 3; // 账号,用户名 + 逗号 + 冒号
        current = current->next;
    }

    // 分配内存
    char *result = malloc(size);
    if (!result) {
        perror("内存分配失败");
        return NULL;
    }

    // 构建列表
    strcpy(result, "ONLINE:");
    current = online_list;
    while (current != NULL) {
        strcat(result, current->account);
        strcat(result, ",");
        strcat(result, current->username);

        if (current->next != NULL) {
            strcat(result, ":");
        }

        current = current->next;
    }
    return result;
}

// 查找在线用户
struct online_user *find_online_user(const char *account) {
    struct online_user *current = online_list;
    while (current != NULL) {
        if (strcmp(current->account, account) == 0) {
            return current;
        }
        current = current->next;
    }
    return NULL;
}

// 检查账号是否唯一
bool is_account_unique(const char *account) {
    FILE *fp = fopen(FILENAME, "r");
    if (!fp) {
        return true;
    }

    char line[256];
    bool unique = true;

    while (fgets(line, sizeof(line), fp)) {
        char saved_account[ACCOUNT_LENGTH + 1];
        if (sscanf(line, "%10[^,]", saved_account) == 1) {
            if (strcmp(saved_account, account) == 0) {
                unique = false;
                break;
            }
        }
    }

    fclose(fp);
    return unique;
}

// 生成唯一账号
bool generate_unique_account(int socket_fd, char *account_out) {
    int attempts = 0;
    char account[ACCOUNT_LENGTH + 1] = {0};

    do {
        for (int i = 0; i < ACCOUNT_LENGTH; i++) {
            account[i] = '0' + rand() % 10;
        }
        account[ACCOUNT_LENGTH] = '\0';

        if (is_account_unique(account)) {
            if (send(socket_fd, account, ACCOUNT_LENGTH + 1, 0) < 0) {
                perror("发送账号失败");
                return false;
            }
            strcpy(account_out, account);
            return true;
        }

        attempts++;
    } while (attempts < MAX_ATTEMPTS);

    const char *error_msg = "无法生成唯一账号";
    send(socket_fd, error_msg, strlen(error_msg), 0);
    return false;
}

// 保存用户信息
void save_user_info(const char *account, const char *username, const char *password) {
    FILE *fp = fopen(FILENAME, "a");
    if (!fp) {
        perror("无法打开用户文件");
        return;
    }

    fprintf(fp, "%s,%s,%s\n", account, username, password);
    fclose(fp);
}

// 验证登录信息
int verify_login(const struct login_info *login_data, char *account_out, char *username_out) {
    FILE *fp = fopen(FILENAME, "r");
    if (!fp) {
        return -1;
    }

    char line[256];
    int result = 1; // 默认登录失败

    while (fgets(line, sizeof(line), fp)) {
        char saved_account[ACCOUNT_LENGTH + 1];
        char saved_username[30];
        char saved_password[30];

        if (sscanf(line, "%10[^,],%29[^,],%29s", saved_account, saved_username, saved_password) == 3) {
            if (strcmp(login_data->identifier, saved_account) == 0 ||
                strcmp(login_data->identifier, saved_username) == 0) {
                if (strcmp(login_data->password, saved_password) == 0) {
                    strcpy(account_out, saved_account);
                    strcpy(username_out, saved_username);
                    result = 0; // 登录成功
                    break;
                }
            }
        }
    }

    fclose(fp);
    return result;
}

// 设置socket非阻塞
void set_nonblocking(int sockfd) {
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags < 0) {
        perror("fcntl(F_GETFL)失败");
        return;
    }
    if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0) {
        perror("fcntl(F_SETFL)失败");
    }
}

// 添加新客户端
void add_client(int socket_fd, struct sockaddr_in client_addr) {
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (clients[i] == NULL) {
            struct client_context *new_client = malloc(sizeof(struct client_context));
            if (!new_client) {
                perror("分配客户端内存失败");
                return;
            }
            
            new_client->socket_fd = socket_fd;
            new_client->client_addr = client_addr;
            strcpy(new_client->ip, inet_ntoa(client_addr.sin_addr));
            new_client->port = ntohs(client_addr.sin_port);
            new_client->state = STATE_NORMAL;
            memset(new_client->current_account, 0, sizeof(new_client->current_account));
            memset(new_client->current_username, 0, sizeof(new_client->current_username));
            memset(new_client->generated_account, 0, sizeof(new_client->generated_account));
            
            clients[i] = new_client;
            client_count++;
            return;
        }
    }
    
    printf("达到最大客户端连接数\n");
    close(socket_fd);
}

// 移除客户端
void remove_client(int socket_fd) {
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (clients[i] != NULL && clients[i]->socket_fd == socket_fd) {
            remove_online_user(socket_fd);
            free(clients[i]);
            clients[i] = NULL;
            client_count--;
            close(socket_fd);
            return;
        }
    }
}

// 处理客户端消息
void handle_client_message(struct client_context *client) {
    char buf[1024];
    ssize_t ret = recv(client->socket_fd, buf, sizeof(buf) - 1, 0);
    
    if (ret <= 0) {
        if (ret == 0 || (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))) {
            // 客户端正常关闭或暂时无数据
            return;
        }
        perror("recv失败");
        remove_client(client->socket_fd);
        return;
    }
    
    buf[ret] = '\0';
    
    if (client->state == STATE_NORMAL) {
        if (strcmp(buf, "REGISTER") == 0) {
            if (generate_unique_account(client->socket_fd, client->generated_account)) {
                client->state = STATE_WAITING_FOR_REG_INFO;
            }
        } 
        else if (strcmp(buf, "LOGIN") == 0) {
            client->state = STATE_WAITING_FOR_LOGIN_INFO;
        } 
        else if (strcmp(buf, "LIST") == 0) {
            char *online_users = get_online_users();
            if (online_users) {
                send(client->socket_fd, online_users, strlen(online_users), 0);
                free(online_users);
            }
        } 
        else if (strncmp(buf, "PRIVATE:", 8) == 0) {
            char recipient[ACCOUNT_LENGTH + 1] = {0};
            char message[256] = {0};

            if (sscanf(buf + 8, "%10[^:]:%255[^\n]", recipient, message) == 2) {
                struct online_user *target = find_online_user(recipient);
                if (target) {
                    char formatted_msg[300];
                    snprintf(formatted_msg, sizeof(formatted_msg), "PRIVATE:%s:%s", 
                             client->current_account, message);
                    send(target->socket_fd, formatted_msg, strlen(formatted_msg), 0);
                    send(client->socket_fd, "消息已发送", 12, 0);
                } else {
                    send(client->socket_fd, "用户不在线", 12, 0);
                }
            }
        } 
        else {
            // 广播消息
            char broadcast_msg[1024];
            snprintf(broadcast_msg, sizeof(broadcast_msg), "[%s]: %s", 
                     client->current_username, buf);

            struct online_user *current = online_list;
            while (current != NULL) {
                if (current->socket_fd != client->socket_fd) {
                    send(current->socket_fd, broadcast_msg, strlen(broadcast_msg), 0);
                }
                current = current->next;
            }
        }
    } 
    else if (client->state == STATE_WAITING_FOR_REG_INFO) {
        if (ret == sizeof(struct account_info)) {
            struct account_info acc_info;
            memcpy(&acc_info, buf, sizeof(struct account_info));

            if (strlen(acc_info.a) == ACCOUNT_LENGTH) {
                save_user_info(acc_info.a, acc_info.user_name, acc_info.password);
                char success_msg[100];
                snprintf(success_msg, sizeof(success_msg), "注册成功! 账号: %s, 用户名: %s",
                         acc_info.a, acc_info.user_name);
                send(client->socket_fd, success_msg, strlen(success_msg), 0);
            } else {
                send(client->socket_fd, "无效的账号格式", 15, 0);
            }
            client->state = STATE_NORMAL;
        }
    } 
    else if (client->state == STATE_WAITING_FOR_LOGIN_INFO) {
        if (ret == sizeof(struct login_info)) {
            struct login_info login_data;
            memcpy(&login_data, buf, sizeof(struct login_info));
            char account[ACCOUNT_LENGTH + 1] = {0};
            char username[30] = {0};

            int login_result = verify_login(&login_data, account, username);
            if (login_result == 0) {
                strcpy(client->current_account, account);
                strcpy(client->current_username, username);

                // 添加到在线用户列表
                add_online_user(account, username, client->socket_fd, client->client_addr);

                // 发送登录成功消息
                char success_msg[100];
                snprintf(success_msg, sizeof(success_msg), "LOGIN_SUCCESS:%s:%s", username, account);
                send(client->socket_fd, success_msg, strlen(success_msg), 0);

                // 发送在线用户列表
                char *online_users = get_online_users();
                if (online_users) {
                    send(client->socket_fd, online_users, strlen(online_users), 0);
                    free(online_users);
                }
            } else {
                send(client->socket_fd, "登录失败: 用户名或密码错误", 28, 0);
            }
            client->state = STATE_NORMAL;
        }
    }
}

int main(int argc, char **argv) {
    srand(time(NULL));
    
    // 初始化客户端数组
    for (int i = 0; i < MAX_CLIENTS; i++) {
        clients[i] = NULL;
    }

    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0) {
        perror("socket创建失败");
        return -1;
    }

    int optval = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    set_nonblocking(socket_fd);  // 设置非阻塞

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT);
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);

    if (bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind失败");
        close(socket_fd);
        return -1;
    }
    printf("服务器已启动: %s:%d\n", SERVER_IP, SERVER_PORT);

    if (listen(socket_fd, 20) < 0) {
        perror("listen失败");
        close(socket_fd);
        return -1;
    }

    fd_set readfds;
    int max_fd = socket_fd;
    
    while (1) {
        FD_ZERO(&readfds);
        FD_SET(socket_fd, &readfds);
        
        // 添加所有客户端socket
        for (int i = 0; i < MAX_CLIENTS; i++) {
            if (clients[i] != NULL) {
                FD_SET(clients[i]->socket_fd, &readfds);
                if (clients[i]->socket_fd > max_fd) {
                    max_fd = clients[i]->socket_fd;
                }
            }
        }
        
        // 等待活动
        int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);
        if (activity < 0 && errno != EINTR) {
            perror("select错误");
            continue;
        }
        
        // 检查新连接
        if (FD_ISSET(socket_fd, &readfds)) {
            struct sockaddr_in client_addr;
            socklen_t addr_len = sizeof(client_addr);
            int new_socket = accept(socket_fd, (struct sockaddr *)&client_addr, &addr_len);
            
            if (new_socket < 0) {
                perror("accept失败");
                continue;
            }
            
            set_nonblocking(new_socket);  // 设置非阻塞
            add_client(new_socket, client_addr);
            
            char *ip = inet_ntoa(client_addr.sin_addr);
            int port = ntohs(client_addr.sin_port);
            printf("新的客户端: [%s][%d]\n", ip, port);
        }
        
        // 处理客户端活动
        for (int i = 0; i < MAX_CLIENTS; i++) {
            if (clients[i] != NULL && FD_ISSET(clients[i]->socket_fd, &readfds)) {
                handle_client_message(clients[i]);
            }
        }
    }

    close(socket_fd);
    return 0;
}